package edu.usm.roberge.ui;

import java.awt.EventQueue;
import java.awt.Font;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Properties;

import javax.swing.ButtonGroup;
import javax.swing.DefaultListModel;
import javax.swing.GroupLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JList;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.GroupLayout.Alignment;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import edu.usm.roberge.model.StockQuoteData;
import edu.usm.roberge.model.StockStore;
import edu.usm.roberge.model.StockStore.PickedStock;
import edu.usm.roberge.model.StockStore.StockStoreListener;
import edu.usm.roberge.ui.QuoteRetrieverWorker.Listener;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Color;

/**
 * Main application class
 * Starts the main application frame
 */
public class Main {

	private JFrame frmStockQuoteAnalyzer;
	private JTextField txtSymbol;
	private JTextField investmentAmt;
	private JLabel lblRefreshing;
	private JLabel refreshingIcon;
	private JLabel lblSelectedSymbol;
	private JLabel lblSelectedLastPrice;
	private JLabel lblSelectedOpenedAt;
	private CalculationWorker worker;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException e1) {
		} catch (InstantiationException e1) {
		} catch (IllegalAccessException e1) {
		} catch (UnsupportedLookAndFeelException e1) {
		}
		
		URL url = Main.class.getClassLoader().getResource("default-stocks.properties");
		
		final Properties props = new Properties();
		try {
			props.load(new FileReader(new File(url.toURI())));
		} catch (FileNotFoundException e1) {
			System.err.println("No properties file found");
		} catch (IOException e1) {
			System.err.println("Could not open properties file");
		} catch (URISyntaxException e) {
			System.err.println("Could not convert properties file to URI");
		}
		
		final DefaultListModel model = new DefaultListModel();
		
		
		final StockStore store = new StockStore(new StockStoreListener() {
			public void onStoreContentChanged(StockQuoteData data) {
				if (model.contains(data)) {
					model.set(model.indexOf(data), data);
				} else {
					model.addElement(data);
				}
			}
		});
		
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Main window = new Main(model, props, store);
					window.frmStockQuoteAnalyzer.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public Main(DefaultListModel model, Properties props, StockStore store) {
		initialize(model, props, store);
		new QuoteRetrieverWorker(props, store, new Listener() {

			public void onUpdatingStockInformationCompleted() {
				lblRefreshing.setVisible(false);
				refreshingIcon.setVisible(false);
			}

			public void onUpdatingStockInformationStarted() {
				lblRefreshing.setVisible(true);
				refreshingIcon.setVisible(true);				
			}
			
		}).execute();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize(DefaultListModel model, final Properties props, final StockStore store) {
		frmStockQuoteAnalyzer = new JFrame();
		frmStockQuoteAnalyzer.setTitle("Stock Quote Analyzer");
		frmStockQuoteAnalyzer.setBounds(100, 100, 723, 485);
		frmStockQuoteAnalyzer.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		JLayeredPane layeredPane = new JLayeredPane();
		
		JLayeredPane layeredPane_1 = new JLayeredPane();
		GroupLayout groupLayout = new GroupLayout(frmStockQuoteAnalyzer.getContentPane());
		groupLayout.setHorizontalGroup(
			groupLayout.createParallelGroup(Alignment.LEADING)
				.addGroup(groupLayout.createSequentialGroup()
					.addContainerGap()
					.addComponent(layeredPane, GroupLayout.PREFERRED_SIZE, 339, GroupLayout.PREFERRED_SIZE)
					.addGap(70)
					.addComponent(layeredPane_1, GroupLayout.DEFAULT_SIZE, 286, Short.MAX_VALUE)
					.addContainerGap())
		);
		groupLayout.setVerticalGroup(
			groupLayout.createParallelGroup(Alignment.TRAILING)
				.addGroup(groupLayout.createSequentialGroup()
					.addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
						.addGroup(Alignment.LEADING, groupLayout.createSequentialGroup()
							.addContainerGap()
							.addComponent(layeredPane, GroupLayout.DEFAULT_SIZE, 433, Short.MAX_VALUE))
						.addGroup(groupLayout.createSequentialGroup()
							.addGap(12)
							.addComponent(layeredPane_1, GroupLayout.PREFERRED_SIZE, 432, GroupLayout.PREFERRED_SIZE)))
					.addContainerGap())
		);
		
		JLabel lblMonitoredStocks = new JLabel("Monitored Stocks");
		
		JScrollPane scrollPane = new JScrollPane();
		
		final JList stocksList = new JList(model);
		scrollPane.setViewportView(stocksList);
		stocksList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		stocksList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
			public void valueChanged(ListSelectionEvent e) {
				StockQuoteData data = (StockQuoteData)stocksList.getSelectedValue();
				lblSelectedSymbol.setText(data.getSymbol());
				lblSelectedLastPrice.setText(data.getLast());
				lblSelectedOpenedAt.setText(data.getOpen());
			}
		});
		
		JLabel lblSymbol_1 = new JLabel("Symbol:");
		
		JLabel lblNewLabel = new JLabel("Last Price:");
		
		JLabel lblOpenedAt = new JLabel("Opened At:");
		
		txtSymbol = new JTextField();
		txtSymbol.setColumns(10);
		
		JLabel lblStockInformation = new JLabel("Stock Information:");
		lblStockInformation.setHorizontalAlignment(SwingConstants.CENTER);
		lblStockInformation.setFont(new Font("Tahoma", Font.BOLD, 14));
		
		JButton btnAddSymbol = new JButton("Add Symbol");
		btnAddSymbol.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				String symbol = txtSymbol.getText();
				if (symbol != null && !symbol.isEmpty()) {
					props.put(symbol, symbol);
					txtSymbol.setText("");
				}
			}
		});
		
		lblRefreshing = new JLabel("Refreshing...");
		lblRefreshing.setVisible(false);
		ImageIcon icon = new ImageIcon(Main.class.getClassLoader().getResource("ajax-loader.gif"));
		refreshingIcon = new JLabel(icon);
		refreshingIcon.setVisible(false);
		
		lblSelectedSymbol = new JLabel("");
		lblSelectedLastPrice = new JLabel("");
		lblSelectedOpenedAt = new JLabel("");
		
		GroupLayout gl_layeredPane_1 = new GroupLayout(layeredPane_1);
		gl_layeredPane_1.setHorizontalGroup(
			gl_layeredPane_1.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_layeredPane_1.createSequentialGroup()
					.addGroup(gl_layeredPane_1.createParallelGroup(Alignment.LEADING)
						.addGroup(gl_layeredPane_1.createSequentialGroup()
							.addContainerGap()
							.addComponent(btnAddSymbol))
						.addGroup(gl_layeredPane_1.createSequentialGroup()
							.addContainerGap()
							.addComponent(txtSymbol, GroupLayout.PREFERRED_SIZE, 142, GroupLayout.PREFERRED_SIZE))
						.addGroup(gl_layeredPane_1.createParallelGroup(Alignment.LEADING)
							.addGroup(gl_layeredPane_1.createSequentialGroup()
								.addGroup(gl_layeredPane_1.createSequentialGroup()
									.addContainerGap()
									.addGroup(gl_layeredPane_1.createParallelGroup(Alignment.TRAILING)
										.addComponent(lblNewLabel)
										.addComponent(lblSymbol_1)
										.addComponent(lblOpenedAt))
									.addPreferredGap(ComponentPlacement.RELATED)
									.addGroup(gl_layeredPane_1.createParallelGroup(Alignment.LEADING)
										.addComponent(lblSelectedOpenedAt)
										.addComponent(lblSelectedLastPrice)
										.addComponent(lblSelectedSymbol)))
								.addPreferredGap(ComponentPlacement.RELATED, 30, Short.MAX_VALUE))
							.addComponent(lblStockInformation, GroupLayout.DEFAULT_SIZE, 290, Short.MAX_VALUE)))
					.addContainerGap(30, Short.MAX_VALUE))
				.addGroup(gl_layeredPane_1.createSequentialGroup()
					.addContainerGap()
					.addComponent(lblMonitoredStocks)
					.addContainerGap(198, Short.MAX_VALUE))
				.addGroup(gl_layeredPane_1.createSequentialGroup()
					.addContainerGap()
					.addComponent(refreshingIcon)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(lblRefreshing)
					.addContainerGap(190, Short.MAX_VALUE))
				.addGroup(gl_layeredPane_1.createSequentialGroup()
					.addContainerGap()
					.addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 276, Short.MAX_VALUE))
		);
		gl_layeredPane_1.setVerticalGroup(
			gl_layeredPane_1.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_layeredPane_1.createSequentialGroup()
					.addComponent(lblMonitoredStocks)
					.addGap(11)
					.addComponent(scrollPane, GroupLayout.PREFERRED_SIZE, 189, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addGroup(gl_layeredPane_1.createParallelGroup(Alignment.BASELINE)
						.addComponent(lblRefreshing)
						.addComponent(refreshingIcon))
					.addGap(26)
					.addComponent(lblStockInformation)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addGroup(gl_layeredPane_1.createParallelGroup(Alignment.BASELINE)
						.addComponent(lblSymbol_1)
						.addComponent(lblSelectedSymbol))
					.addPreferredGap(ComponentPlacement.RELATED)
					.addGroup(gl_layeredPane_1.createParallelGroup(Alignment.BASELINE)
						.addComponent(lblNewLabel)
						.addComponent(lblSelectedLastPrice))
					.addPreferredGap(ComponentPlacement.RELATED)
					.addGroup(gl_layeredPane_1.createParallelGroup(Alignment.BASELINE)
						.addComponent(lblOpenedAt)
						.addComponent(lblSelectedOpenedAt))
					.addGap(18)
					.addComponent(txtSymbol, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(btnAddSymbol))
		);
		layeredPane_1.setLayout(gl_layeredPane_1);
		
		JLabel lblSelectStock = new JLabel("Selected Stock");
		lblSelectStock.setHorizontalAlignment(SwingConstants.CENTER);
		lblSelectStock.setFont(new Font("Tahoma", Font.BOLD, 14));
		
		JLabel lblSymbol = new JLabel("Symbol:");
		
		JLabel lblNumberOwned = new JLabel("Number Owned:");
		
		JLabel lblProfit = new JLabel("Profit:");
		
		JLabel lblHowMuchDo = new JLabel("How much do you want to invest? (e.g. $100)");
		
		investmentAmt = new JTextField();
		investmentAmt.setColumns(10);
		
		JLabel lblPickAStock = new JLabel("Pick a stock based on:");
		
		final JRadioButton rdbtnShowMeThe = new JRadioButton("The most I can own");
		JRadioButton rdbtnShowMeThe_1 = new JRadioButton("The biggest dividend");
		final ButtonGroup bg = new ButtonGroup();
		bg.add(rdbtnShowMeThe);
		bg.add(rdbtnShowMeThe_1);
		
		final JLabel lblBadValue = new JLabel("Bad value");
		lblBadValue.setFont(new Font("Tahoma", Font.BOLD, 11));
		lblBadValue.setForeground(Color.RED);
		lblBadValue.setVisible(false);

		
		final JLabel lblPickedSymbol = new JLabel("");
		final JLabel lblPickedNumOwned = new JLabel("");
		final JLabel lblPickedProfit = new JLabel("");
		
		final JButton btnPickStock = new JButton("Pick Stock");
		btnPickStock.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if (worker != null && !worker.isDone()) {
					return; // worker already started and still calcing...
				}
				
				btnPickStock.setEnabled(false);
				String investmentAmount = investmentAmt.getText();
				if (investmentAmount == null || investmentAmount.isEmpty() || !investmentAmount.startsWith("$")) {
					lblBadValue.setVisible(true);
					btnPickStock.setEnabled(true);
				} else {
					lblBadValue.setVisible(false);
					CalculationWorker.Algorithm algorithm = null;
					if (bg.getSelection().isSelected()) {
						if (rdbtnShowMeThe.isSelected()) {
							algorithm = CalculationWorker.Algorithm.MOST_SHARES;
						} else {
							algorithm = CalculationWorker.Algorithm.MOST_PROFIT;
						}
					} else {
						return;
					}
					double investAmt = Double.parseDouble(investmentAmount.substring(1));
					worker = new CalculationWorker(investAmt, store, new CalculationWorker.Listener() {
						public void onSelectedStock(PickedStock data) {
							lblPickedSymbol.setText(data.getSymbol());
							lblPickedNumOwned.setText(data.getNumberOfShares());
							lblPickedProfit.setText(data.getProfit());
							btnPickStock.setEnabled(true);
						}
					}, algorithm);
					worker.execute();
				}
			}
		});

		GroupLayout gl_layeredPane = new GroupLayout(layeredPane);
		gl_layeredPane.setHorizontalGroup(
			gl_layeredPane.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_layeredPane.createSequentialGroup()
					.addContainerGap()
					.addGroup(gl_layeredPane.createParallelGroup(Alignment.LEADING)
						.addComponent(lblSelectStock, GroupLayout.DEFAULT_SIZE, 329, Short.MAX_VALUE)
						.addGroup(gl_layeredPane.createSequentialGroup()
							.addGroup(gl_layeredPane.createParallelGroup(Alignment.LEADING)
								.addComponent(rdbtnShowMeThe_1)
								.addGroup(gl_layeredPane.createSequentialGroup()
									.addGap(40)
									.addComponent(lblSymbol)
									.addPreferredGap(ComponentPlacement.RELATED)
									.addComponent(lblPickedSymbol))
								.addComponent(lblHowMuchDo)
								.addGroup(gl_layeredPane.createSequentialGroup()
									.addComponent(investmentAmt, GroupLayout.PREFERRED_SIZE, 153, GroupLayout.PREFERRED_SIZE)
									.addPreferredGap(ComponentPlacement.RELATED)
									.addComponent(lblBadValue))
								.addComponent(lblPickAStock)
								.addComponent(rdbtnShowMeThe))
							.addContainerGap(109, Short.MAX_VALUE))
						.addGroup(gl_layeredPane.createSequentialGroup()
							.addGroup(gl_layeredPane.createParallelGroup(Alignment.TRAILING)
								.addComponent(lblProfit)
								.addComponent(lblNumberOwned))
							.addPreferredGap(ComponentPlacement.RELATED)
							.addGroup(gl_layeredPane.createParallelGroup(Alignment.LEADING)
								.addComponent(lblPickedNumOwned)
								.addComponent(lblPickedProfit))
							.addContainerGap(245, Short.MAX_VALUE))
						.addGroup(gl_layeredPane.createSequentialGroup()
							.addComponent(btnPickStock)
							.addContainerGap(248, Short.MAX_VALUE))))
		);
		gl_layeredPane.setVerticalGroup(
			gl_layeredPane.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_layeredPane.createSequentialGroup()
					.addContainerGap()
					.addComponent(lblHowMuchDo)
					.addGap(6)
					.addGroup(gl_layeredPane.createParallelGroup(Alignment.BASELINE)
						.addComponent(investmentAmt, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
						.addComponent(lblBadValue))
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(lblPickAStock)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(rdbtnShowMeThe)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(rdbtnShowMeThe_1)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(btnPickStock)
					.addGap(89)
					.addComponent(lblSelectStock)
					.addGap(18)
					.addGroup(gl_layeredPane.createParallelGroup(Alignment.BASELINE)
						.addComponent(lblSymbol)
						.addComponent(lblPickedSymbol))
					.addPreferredGap(ComponentPlacement.RELATED)
					.addGroup(gl_layeredPane.createParallelGroup(Alignment.BASELINE)
						.addComponent(lblNumberOwned)
						.addComponent(lblPickedNumOwned))
					.addPreferredGap(ComponentPlacement.RELATED)
					.addGroup(gl_layeredPane.createParallelGroup(Alignment.BASELINE)
						.addComponent(lblProfit)
						.addComponent(lblPickedProfit))
					.addContainerGap(111, Short.MAX_VALUE))
		);
		layeredPane.setLayout(gl_layeredPane);
		frmStockQuoteAnalyzer.getContentPane().setLayout(groupLayout);
	}
}
